package com.avic.tools.utils;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;


public class ExcelParser {
    /**
     *Excel文件
     */
    private File file;

    /**
     * Workbook接口，用于根据条件实例化不同的实现类
     */
    private Workbook ExcelWorkbook = null;

    public ExcelParser(String filepath ) {

        this.file = new File(filepath);
    }

    /**
     * 读取文件，判断文件类型并创建有关实现类来实现Workbook接口。
     */
    public void Read() {
        try (FileInputStream fis = new FileInputStream(file)) {
            if (file.getName().endsWith(".xls")) {
                ExcelWorkbook = new HSSFWorkbook(fis);
            } else if (file.getName().endsWith(".xlsx")) {
                ExcelWorkbook = new XSSFWorkbook(fis);
            } else {
                System.out.println(file.getName()+"不是可以被本类解析的文件");
                return;
            }
        } catch (FileNotFoundException e) {
            System.out.println("文件不存在！");
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取Workbook实现类的指定位置的Sheet实现类信息到Map中,并返回。
     * @param SheetNum Map<Integer,Integer>，存放需要读取的Excel的Sheet的顺序号及其指定行号，如第一个Sheet就写1，第一行就写1
     * @return
     */
    private Map<Integer, Object> GetSheet2Map(Map<Integer,Integer> SheetNum) {
        Map<Integer, Object> SheetMap = new LinkedHashMap<>();
        if (SheetNum == null){
            for (int k = 0; k < ExcelWorkbook.getNumberOfSheets(); k++) {
                Sheet sheet = ExcelWorkbook.getSheetAt(k);
                SheetMap.put((k + 1), sheet.getSheetName());
            }
        }else if(SheetNum != null){
            for (Map.Entry<Integer,Integer> entry:SheetNum.entrySet()) {
                Sheet sheet = ExcelWorkbook.getSheetAt(entry.getKey()-1);
                SheetMap.put((entry.getKey()), sheet.getSheetName());
            }
        }
        return SheetMap;
    }

    /**
     * 将某个工作表的某行转换为标题的Map实现类，并返回
     *
     * @param sheet         要解析的工作表 Sheet对象实现类
     * @param TitleRowIndex 标题位于哪一行
     * @return
     */
    private Map<Integer, Object> GetAnyRow2Title(Sheet sheet, int TitleRowIndex) {
        Map<Integer, Object> TitleMap = new LinkedHashMap<>();
        Row row = sheet.getRow(TitleRowIndex);
        GetCell(sheet, row, TitleMap);
        return TitleMap;
    }

    /**
     * 将将某个工作表的某行转换为除去标题的Map实现类的List集合，并返回
     *
     * @param sheet         要解析的工作表 Sheet对象实现类
     * @param TitleRowIndex 标题位于哪一行，默认标题以下部分是表格主体内容
     * @return
     */
    private List<Map<Integer, Object>> GetRows2ListWithMap(Sheet sheet, int TitleRowIndex) {
        List<Map<Integer, Object>> TableRows = new ArrayList<>();
        int rows = sheet.getPhysicalNumberOfRows();
        for (int r = TitleRowIndex+1; r < rows; r++) {
            Row row = sheet.getRow(r);
            if (row == null) {
                System.out.println("工作表：" + sheet.getSheetName() + ",第" + r + "行为空行！");
            } else if (row != null) {
                if(isColumnEmpty(row)){
                    break;
                }
                Map<Integer, Object> RowMap = new HashMap<>();
                GetCell(sheet, row, RowMap);
                TableRows.add(RowMap);
            }
        }
        return TableRows;
    }


    private boolean isColumnEmpty(Row row){
        for(int i = row.getFirstCellNum(); i <= row.getLastCellNum(); i++)
        {
            Cell cell = row.getCell(i);
            if (cell == null || cell.getCellType() == CellType.BLANK || cell.getCellType() == CellType.STRING && cell.getStringCellValue().trim().isEmpty()) {
                // nothing
            }else{
                return false;
            }
        }
        return true;
    }

    /**
     * 将Sheet、Row接口的实现类转换为特定格式的Map接口的实现类，并返回。
     * 转换后的Map实现类，-1位置作为工作表名，0位置作为行的序号，其余位置按照列的序号存到Map中。
     *
     * @param sheet     当前工作表，Sheet的实现类
     * @param columnrow 当前行，Row的实现类
     * @param columns   要存数据的Map实现类
     */
    private void GetCell(Sheet sheet, Row columnrow, Map<Integer, Object> columns) {
        DataFormatter formatter = new DataFormatter();
        if (columnrow == null) {
            System.out.println(sheet.getSheetName() + "中有空行！");
            return;
        }
        //-1位置作为工作表名
        columns.put(-1, sheet.getSheetName() + "");
        //0位置作为行的序号
        columns.put(0, columnrow.getRowNum() + "");
        //遍历Row对象，获取每行记录的每列
        for (int c = 0; c < columnrow.getLastCellNum(); c++) {
            Cell cell = columnrow.getCell(c);
            Object value = "";
            if (cell != null) {
                switch (cell.getCellType()) {
                    //对不同类型的字段，用不同的方式获取
                    case FORMULA:
                        value = "" + cell.getCellFormula();
                        break;

                    case NUMERIC:
//                        value = cell.getNumericCellValue();
                        value = formatter.formatCellValue(cell);
                        break;

                    case STRING:
                        value = cell.getStringCellValue();
                        break;

                    case BLANK:
                        value = "<BLANK>";
                        break;

                    case BOOLEAN:
                        value = "" + cell.getBooleanCellValue();
                        break;

                    case ERROR:
                        value = "" + cell.getErrorCellValue();
                        break;

                    default:
                        value = "" + cell.getCellType();
                }
                //其余位置按照列的序号存到Map中
                columns.put(cell.getColumnIndex() + 1, value);
            }
        }
    }

    /**
     * 根据工作表的序号获取ExcelBean的实体类对象
     * @return ExcelBean
     */
    public List<ExcelBean> GetExcelBean(Map<Integer,Integer> SheetNum) {
        List<ExcelBean> excelBeans = new ArrayList<>();
        if(ExcelWorkbook != null){
            //获取所有工作表名称
            Map<Integer,Object> TitleMap = GetSheet2Map(SheetNum);
            //以工作表为单位来读取数据为实体类
            for(Map.Entry<Integer,Object> entry:TitleMap.entrySet()){
                ExcelBean excelBean = new ExcelBean();
                //将TitleMap的值写入工作表属性
                excelBean.setSheetname(entry.getValue().toString());
                //根据TitleMap的键获取Sheet对象
                Sheet sheet = ExcelWorkbook.getSheetAt(entry.getKey()-1);
                //默认行号为0
                int TitleNum = 0;
                if(SheetNum != null){
                    //根据TitleMap的键到SheetNum中获取指定的行号
                    TitleNum = SheetNum.get(entry.getKey())-1;
                }
                excelBean.setColumntitle(GetAnyRow2Title(sheet,TitleNum));
                excelBean.setRows(GetRows2ListWithMap(sheet,TitleNum));
                excelBeans.add(excelBean);
            }
        }else if(ExcelWorkbook == null){
            System.out.println("获取Workbook失败！");
        }

        return excelBeans;
    }

    /**
     * 关闭Workbook对象
     */
    public void Close(){
        try {
            ExcelWorkbook.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
